#pragma once

#include <stack>
#include <map>

#include "kobj.h"

typedef void (*OP_EXECUTOR)();
typedef void (*FUNC_EXECUTOR)();

#define MAX_TAPE 128

class KVM
{
protected:
	static bool IsRunning;
	static k_int Line;
	static k_uint IP;

	static const unsigned char *Code;
	static const char *Pool;
	static k_uint CodeSize;

	static std::map<k_int, KObject> Variables;
	static std::stack<KObject> evalStack;
	static std::stack<KObject> kStack;
	static KObject kTape[MAX_TAPE];
	static k_int kTapePtr;

	static std::stack<k_uint> CallStack;

	static KObject EmptyString;

	static OP_EXECUTOR Executors[256];
	static OP_EXECUTOR DefaultExecutors[];

	static FUNC_EXECUTOR BuiltinFunctions[];

protected:
	static void do_nop();
	static void do_ldi();
	static void do_ldr();
	static void do_lds();
	static void do_ldes();
	static void do_ldvar();
	static void do_stvar();
	static void do_new();
	static void do_free();
	static void do_cvi();
	static void do_cvr();
	static void do_cvs();
	static void do_cvin();
	static void do_cvrn();
	static void do_in();
	static void do_out();
	static void do_push();
	static void do_pop();
	static void do_stf();
	static void do_smv();
	static void do_swap();
	static void do_sclr();
	static void do_sclrc();
	static void do_trd();
	static void do_trdx();
	static void do_twr();
	static void do_twrx();
	static void do_tnxt();
	static void do_tprv();
	static void do_tmov();
	static void do_jmp();
	static void do_cjmp();
	static void do_call();
	static void do_ccall();
	static void do_ret();
	static void do_hlt();
	static void do_add();
	static void do_sub();
	static void do_mul();
	static void do_div();
	static void do_idiv();
	static void do_mod();
	static void do_pow();
	static void do_equ();
	static void do_neq();
	static void do_lt();
	static void do_lte();
	static void do_gt();
	static void do_gte();
	static void do_cat();
	static void do_and();
	static void do_or();
	static void do_xor();
	static void do_not();
	static void do_neg();
	static void do_func();
	static void do_trace();
	static void do_illegal();

	static void f_abs();
	static void f_sqrt();
	static void f_sin();
	static void f_cos();
	static void f_tan();
	static void f_asin();
	static void f_acos();
	static void f_atan();
	static void f_chr();
	static void f_asc();
	static void f_len();
	static void f_left();
	static void f_mid();
	static void f_right();
	static void f_iif();
	static void f_tape();
	static void f_stack();
	static void f_pop();
	static void f_peek();

	static void PrepareExecutors();

public:
	static bool Run(const unsigned char *code, k_uint codeSize, const char *pool);
};
